package org.m2acsi.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.validation.constraints.Size;
import org.m2acsi.utils.PrettyDate;

@Entity(name = "Tasks")
public class Task implements Serializable {

    private Long id;
    private String title;
    private String description;
    private Date deadline;
    private User author;
    private List<Consultation> consultations;
    private List<User> contributors;
    private List<Message> messages;
    private List<Opinion> opinions;
    private List<Document> documents;
    private Date creationDate;
    private int notifications;
    private boolean closedByAdmin;

    public Task() {
        this.creationDate = new Date();
        this.consultations = new ArrayList<>();
        this.contributors = new ArrayList<>();
        this.messages = new ArrayList<>();
        this.opinions = new ArrayList<>();
        this.documents = new ArrayList<>();
        this.notifications = 0;
        this.closedByAdmin = false;
    }

    public Task(String title, String description, Date deadline) {
        this();
        this.title = title;
        this.description = description;
        this.deadline = deadline;
    }

    public Task(String title, String description, Date deadline, User author) {
        this(title, description, deadline);
        this.author = author;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Size(min = 1, max = 200)
    @Column(nullable = false, length = 200)
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Size(min = 1, max = 5000)
    @Column(nullable = false, length = 5000)
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Temporal(TemporalType.DATE)
    @Column(nullable = false)
    public Date getDeadline() {
        return deadline;
    }

    public void setDeadline(Date deadline) {
        this.deadline = deadline;
    }

    @ManyToOne
    @JoinColumn(name = "AUTHOR_ID", nullable = false, updatable = false)
    public User getAuthor() {
        return author;
    }

    public void setAuthor(User author) {
        this.author = author;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "task")
    public List<Consultation> getConsultations() {
        return consultations;
    }

    public void setConsultations(List<Consultation> consultations) {
        this.consultations = consultations;
    }

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "contributions")
    public List<User> getContributors() {
        return contributors;
    }

    public void setContributors(List<User> contributors) {
        this.contributors = contributors;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "task")
    public List<Message> getMessages() {
        return messages;
    }

    public void setMessages(List<Message> messages) {
        this.messages = messages;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "task")
    public List<Opinion> getOpinions() {
        return opinions;
    }

    public void setOpinions(List<Opinion> opinions) {
        this.opinions = opinions;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "task")
    public List<Document> getDocuments() {
        return documents;
    }

    public void setDocuments(List<Document> documents) {
        this.documents = documents;
    }

    @Temporal(TemporalType.DATE)
    @Column(nullable = false, updatable = false)
    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public String getPrettyDeadline() {
        return PrettyDate.transform(deadline);
    }

    public String getDeadlineStatus() {
        if (deadline.compareTo(new Date()) > 0) {
            return "Ends " + PrettyDate.transform(deadline).toLowerCase();
        } else {
            return "Ended " + PrettyDate.transform(deadline).toLowerCase();
        }
    }

    public String getIndexTimeLeft() {
        if (PrettyDate.rawTimeLeft(deadline) < 360000000) {
            return "(" + PrettyDate.timeLeft(deadline) + " left)";
        } else {
            return "";
        }
    }

    public String getTimeLeft() {
        return PrettyDate.timeLeft(deadline);
    }

    public boolean isFinished() {
        return deadline.compareTo(new Date()) > 0;
    }

    @Override
    public String toString() {
        return "Task{" + "id=" + id + ", title=" + title + ", description=" + description + ", deadline=" + deadline + ", author=" + author.getEmail() + ", consultations=" + consultations + ", contributors=" + contributors.size() + ", messages=" + messages.size() + ", opinions=" + opinions.size() + ", documents=" + documents.size() + ", creationDate=" + creationDate + '}';
    }

    @Transient
    public int getNotifications() {
        return notifications;
    }

    public void setNotifications(int notifications) {
        this.notifications = notifications;
    }

    public boolean isClosedByAdmin() {
        return closedByAdmin;
    }

    public void setClosedByAdmin(boolean closedByAdmin) {
        this.closedByAdmin = closedByAdmin;
    }

}
